﻿using System;
using System.Collections.Generic;
using System.Text;
using Tao.OpenGl;
using Tao.DevIl;

namespace Ommf
{
    public class Image : IDrawable
    {
        private int glTexture;
        private int width;
        private int height;
        private float centerX = 0;
        private float centerY = 0;
        private ImageFilter filter;
        private bool disposed = false;

        internal Image(string filename)
        {
            int ilTex = Il.ilGenImage();
            Il.ilBindImage(ilTex);

            if (Il.ilLoadImage(filename)) //was image load successful?
            {
                Il.ilConvertImage(Il.IL_RGBA, Il.IL_UNSIGNED_BYTE);

                width = Il.ilGetInteger(Il.IL_IMAGE_WIDTH);
                height = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT);
                
                Gl.glGenTextures(1, out glTexture);
                Bind();

                this.Filter = ImageFilter.Linear;
                //Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP_TO_EDGE);
                //Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_EDGE);
                
                Gl.glTexImage2D(
                    Gl.GL_TEXTURE_2D, 0, Il.ilGetInteger(Il.IL_IMAGE_BPP),
                    width, height, 0, Il.ilGetInteger(Il.IL_IMAGE_FORMAT),
                    Gl.GL_UNSIGNED_BYTE, Il.ilGetData());
            }

            Il.ilDeleteImage(ilTex);
        }

        public void Dispose()
        {
            Gl.glDeleteTextures(1, new int[] { glTexture });
            disposed = true;
        }

        internal void Bind()
        {
            Gl.glBindTexture(Gl.GL_TEXTURE_2D, glTexture);
        }

        public void SetCenter(float x, float y)
        {
            centerX = x;
            centerY = y;
        }

        #region IDrawable Members

        public void Draw(float x, float y, float angle, float scaleX, float scaleY)
        {
            Gl.glColor4ub(255, 255, 255, 255);
            Bind();

            Gl.glPushMatrix();

            Gl.glTranslatef(x, y, 0);
            Gl.glRotatef(angle, 0, 0, 1);
            Gl.glScalef(scaleX, scaleY, 1.0f);
            Gl.glTranslatef(-centerX, -centerY, 0);
            
            Gl.glBegin(Gl.GL_QUADS);
            
            Gl.glTexCoord2f(0.0f, 0.0f); Gl.glVertex3f(0, 0, 0);
            Gl.glTexCoord2f(0.0f, 1.0f); Gl.glVertex3f(0, height, 0);
            Gl.glTexCoord2f(1.0f, 1.0f); Gl.glVertex3f(width, height, 0);
            Gl.glTexCoord2f(1.0f, 0.0f); Gl.glVertex3f(width, 0, 0);
            
            Gl.glEnd();

            Gl.glPopMatrix();
        }

        public void DrawSubrect(float x, float y, float angle, float scaleX, float scaleY, float subX, float subY, float subWidth, float subHeight)
        {
            float tX1 = subX / width;
            float tY1 = subY / height;
            float tX2 = (subX + subWidth) / width;
            float tY2 = (subY + subHeight) / height;

            Gl.glColor4ub(255, 255, 255, 255);
            Bind();

            Gl.glPushMatrix();

            Gl.glTranslatef(x, y, 0);
            Gl.glRotatef(angle, 0, 0, 1);
            Gl.glScalef(scaleX, scaleY, 1.0f);
            Gl.glTranslatef(-centerX, -centerY, 0);

            Gl.glBegin(Gl.GL_QUADS);

            Gl.glTexCoord2f(tX1, tY1); Gl.glVertex3f(0, 0, 0);
            Gl.glTexCoord2f(tX1, tY2); Gl.glVertex3f(0, subHeight, 0);
            Gl.glTexCoord2f(tX2, tY2); Gl.glVertex3f(subWidth, subHeight, 0);
            Gl.glTexCoord2f(tX2, tY1); Gl.glVertex3f(subWidth, 0, 0);

            Gl.glEnd();

            Gl.glPopMatrix();
        }

        #endregion

        public int Width
        {
            get { return width; }
        }

        public int Height
        {
            get { return height; }
        }

        public float CenterX
        {
            get { return centerX; }
        }

        public float CenterY
        {
            get { return centerY; }
        }

        public ImageFilter Filter
        {
            get { return filter; }
            set
            {
                filter = value;
                Bind();
                
                int glFilter = Gl.GL_LINEAR;
                switch (filter)
                {
                    case ImageFilter.Linear:  glFilter = Gl.GL_LINEAR; break;
                    case ImageFilter.Nearest: glFilter = Gl.GL_NEAREST; break;
                }

                Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, glFilter);
                Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, glFilter);
            }
        }

        public bool IsDisposed
        {
            get { return disposed; }
        }
    }
}
